import { sleep, toMap, treeForeach } from '@/util/common';
import { SimulateController } from './Controller';
import { MODEL_SERVER_URL } from '@/constants/constants';
import { SceneData, SceneState } from "./_";
import { RefreshSessionsStatus } from './types/SceneService';

export default class SceneService{

  controller:SimulateController;

  sceneTreeData: SceneData[] = [];
  /** 显示触发列表 */
  showTriggerBox = true;
  refreshSessionsRecord: SceneData[][] = [];
  refreshSessionsStatus = RefreshSessionsStatus.Empty;
  sceneDataMap = new Map<string, SceneData>()

  async serviceInit() {
    this.sceneDataMap.clear();
    this.sceneTreeData.length = 0;
  }

  constructor(controller:SimulateController){
    this.controller = controller as SimulateController;
  }

  async sceneVariableDataInit() {
    const sceneData: SceneData[] = (await this.controller.simApi.sceneFetch({
      fetchAll: true,
      simulationSessionId: this.controller.sessionId,
    })).data?.data;
    if (!sceneData?.length) return;
    this.serviceInit();
    const newSeceneDataMap = await this.AddSceneData(sceneData, this.sceneDataMap);
    if (newSeceneDataMap.size) {
      this.sceneDataMap = newSeceneDataMap;
    }
    if (this.sceneTreeData.length) {
      await this.sceneChange(this.sceneTreeData[0].id);
    }
  }

  async sceneChange(id: string) {
    const actived = this.sceneDataMap.get(this.controller.sceneId);
    if (actived?.id === id) return;
    if (actived) {
      actived.isSelected = false;
    }
    this.controller.sceneId = id;
    const activing = this.sceneDataMap.get(this.controller.sceneId);
    if (activing) {
      activing!.isSelected = true;
    }
    if (activing?.children.length) {
      activing.expand = true;
    }
    console.info("active scene is: ", activing);
    await this.controller.variableService.initSceneVariable();
    await this.controller.toolbarService.getAndSetsignalList();
  }

  async refreshSessions(data: SceneData[]) {
    this.refreshSessionsRecord.push(data);
    if (this.refreshSessionsStatus === RefreshSessionsStatus.Empty) {
      this.refreshSessionsStatus = RefreshSessionsStatus.Refresing;
      const usedRefreshData = this.refreshSessionsRecord.pop();
      this.refreshSessionsRecord.length = 0;
      this.sceneTreeData.length = 0;
      const newSeceneDataMap = await this.AddSceneData(usedRefreshData!, this.sceneDataMap);
      this.sceneDataMap = newSeceneDataMap;
      const selectSecenData = this.sceneDataMap.get(this.controller.sceneId);
      if (!selectSecenData && this.sceneTreeData.length) {
        await this.sceneChange(this.sceneTreeData[0].id);
      }
      setTimeout(() => {
        this.refreshSessionsStatus = RefreshSessionsStatus.Empty;
        if (this.refreshSessionsRecord.length) {
          this.refreshSessions(this.refreshSessionsRecord.pop()!);
        }
      }, 1000);
    }
  }

  async AddSceneData(sceneData: SceneData[], exsitMap: Map<string, SceneData>) {
    const newSeceneDataMap = new Map<string, SceneData>();
    const idsRecord: string[] = [];
    treeForeach(sceneData, (t) => {
      idsRecord.push(t.instanceId);
    });
    const modelInfos = (await this.controller.modelApi.modelInfos({
      projectId: this.controller.projectId,
      modelIds: idsRecord
    })).data?.data;

    // icon
    if (modelInfos && modelInfos.length) {
      const modelMap = toMap(modelInfos);
      treeForeach(sceneData, (t) => {
        const m = modelMap.get(t.instanceId);
        if (m) {
          t.modelVo = m;
          if (m.icon.startsWith('statics/') || m.icon.startsWith(MODEL_SERVER_URL) || m.icon.startsWith('/statics/')) {
            const _prefix = process.env.NODE_ENV === 'development' ? '' : 'app://./';
            t.icon = `${_prefix}${m.icon}`;
          } else {
            t.icon = `${MODEL_SERVER_URL}public/files/${this.controller.projectId}/${m.icon}`;
          }
        }
        if (exsitMap.size) {
          const exsitScene = exsitMap.get(t.id);
          if (exsitScene) {
            t.isSelected = exsitScene.isSelected || false;
            t.expand = exsitScene.expand || false;
          }
        }
        if (!t.state) {
          t.state = SceneState.READY;
        }
        newSeceneDataMap.set(t.id, t);
      });
    }

    this.sceneTreeData = sceneData;
    return newSeceneDataMap;
  }

  switchShowTrigger() {
    this.showTriggerBox = !this.showTriggerBox;
  }

  async refreshSceneStatus(targetId: string, status: SceneState) {
    const target = this.sceneDataMap.get(targetId);
    if (target) {
      target.state = status;
    }
  }
}

